package com.lyf.boot.web.advice;

import cn.hutool.crypto.SecureUtil;
import com.lyf.boot.annotation.Crypto;
import com.lyf.boot.properties.CryptoProperties;
import com.lyf.boot.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @author Luyufan
 * @date 2023/8/15 15:44
 */
@RequiredArgsConstructor
@ControllerAdvice
@Slf4j
public class EncodeResponseBodyAdvice implements ResponseBodyAdvice<Object> {

    private final CryptoProperties cryptoProperties;

    @Override
    public boolean supports(@NonNull MethodParameter returnType, @NonNull Class converterType) {
        return true;
    }

    @Override
    @Nullable
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, @NonNull MediaType mediaType, @NonNull Class clazz, @NonNull ServerHttpRequest request, @NonNull ServerHttpResponse response) {
        boolean outEncode = false;
        boolean outPrint = false;
        if(Objects.requireNonNull(methodParameter.getMethod()).getDeclaringClass().isAnnotationPresent(Crypto.class)){
            Crypto crypto = methodParameter.getDeclaringClass().getAnnotation(Crypto.class);
            outEncode = crypto.outEncode();
            outPrint = crypto.outEncode();
        }
        if(methodParameter.getMethod().isAnnotationPresent(Crypto.class)){
            Crypto crypto = methodParameter.getMethodAnnotation(Crypto.class);
            assert crypto != null;
            outEncode = crypto.outEncode();
            outPrint = crypto.outEncode();
        }
        String result = JsonUtil.toJsonString(body);
        if(cryptoProperties.isEnabled()){
            if(outPrint){
                //输出内容，比较耗性能，建议只在开发环境开启
                log.debug("加密前出参：\n{}", result);
            }
            if(outEncode){
                return SecureUtil.aes(cryptoProperties.getAseKey().getBytes()).encrypt(result, StandardCharsets.UTF_8);
            }
        }
        return body;
    }
}
